一覧に戻る

ReactやVueでレイヤー管理する際のプラクティス

#TypeScript#foss4g#Vue.js#React#MapLibre

TL;DR

  • モダンなウェブフレームワークでは、「宣言的」なコードがうれしい
  • Map.addLayer/removeLayerを利用すると「手続き的」なコードとなってしまう
  • Map.setStyle(newStyle)を利用すると、宣言的にレイヤーを定義できる

はじめに

MapLibre User Group Japanの@Kanahiroです。

MapLibreとは、モダンなWeb地図にまつわるOSSを傘下に収める開発者コミュニティです。

この記事について

現代のWeb開発ではもはや、ReactやVueといったフレームワーク(ないしライブラリ)の利用は当たり前となりました。当然、MapLibre GL JSを利用する場合はそれらと組み合わせて開発するわけですが、適切なAPIを用いた「ちょっと賢そうな」実装を紹介します。

モダンなフレームワークと地図ライブラリ

ReactやVue、最近ではSvelteが人気ですが、これらは、JavaScriptの変数とUIを同期させやすくしている、と理解できると思います。これは、JavaScriptの変数を監視して変更をUIに反映している…、と言えます。

graph LR

JavaScriptの変数 --変更を検知--> UIを更新

UIがDOMなら、フレームワークの作法に沿うだけで、簡単にUIを更新出来るでしょう。しかし地図ライブラリの場合はちょっと違って:

graph LR

JavaScriptの変数 --変更を検知--> 地図ライブラリの関数を実行

となります。LeafletやMapLibre GL JSだとaddLayerなんて関数があり、これを利用するようなコードを書くことになります。Reactだと以下のようになるでしょうか(疑似コードです)

// layersという、表示するレイヤーを保存する配列があるとして
useEffect(() => {
    const newLayer = getNewLayer(layers); // 追加されたレイヤーだけを抽出
    map.addLayer(newLayer);
}, [layers])

もちろんremoveLayerの場合も考慮する必要があるでしょう。

この実装はかなり面倒です:

  1. layersの変更を検知して、何が増えたのか・何が減ったのか、判別する必要がある
  2. すでに存在する(しない)レイヤーをadd(remove)してしまうとエラーが起きるので、存在チェックが必要

という問題があるためです。

これらの根本原因は、フレームワークで監視している「状態」と、mapインスタンス内の「状態」が独立しているためです。

MapLibre GL JSのちょっと賢いレイヤー管理

MapLibre GL JSではMap.setStyle(newStyle)という関数が提供されています。変更後のスタイルを引数として関数を実行すると、地図の状態がそのスタイルの状態に書きかわります。

https://maplibre.org/maplibre-gl-js/docs/API/classes/maplibregl.Map/#setstyle

なのでさっきと同様に疑似コードを書くと

// mapStyleという、地図スタイルを保持する変数があるとして
const [mapStyle, setMapStyle] = useState({
    version: 8,
    layers: [],
    source: {}
});
useEffect(() => {
    map.setStyle(mapStyle);
}, [mapStyle])

となります。こうすると、たとえばmapStyle.layersが変化したら、map.setStyle(mapStyle)が実行され、mapに新しいスタイルが適用されることになります。するとさっきに比べて:

  1. 何が増えたのか・減ったのか、考える必要がない
  2. すでに存在する(しない)レイヤーをadd(remove)してしまうことはない

という嬉しいことがあります。これは常に「表示すべき地図スタイルを定義すればよい」ということです。すなわち「宣言的」なコードとなります。どれだけたくさんのレイヤーがあっても、管理しやすいコードになるでしょう。

なお、setStyleは、前後の差分のみを変更する処理を行うので、パフォーマンスにも優れています(=全てのレイヤーを削除して再追加したりしない)。

終わりに

地図ライブラリはモダンなフレームワークでは「副作用」であるため、うまく使わないと色々難しいことが起きると思います。今回の記事でうまく使う手法を紹介しました。

また、たとえばReactならreact-map-glというライブラリがあります。

https://github.com/visgl/react-map-gl

これはまさに、「副作用」をラップしてReactの「宣言的な世界」で使いやすくしているものです。こういったライブラリを利用するのも、よいプラクティスです。